#ifndef _PROJECT_H_
#define _PROJECT_H_

#include "./getsym.h"
#include <vector>

using namespace std;

//文法符号
struct sign {
  string name;
  int type; //0为终结符，1为非终结符
  std::vector<string> first;
  std::vector<string> follow;

  sign(){};
  sign(string s);
  void add_to_first(string s);
  void add_to_follow(string s);
  bool could_disappear();  //是否可以由该符号推导出空


  void operator = (const sign &s) {
    name = s.name;
    type = s.type;
    first.assign(s.first.begin(),s.first.end());
    follow.assign(s.follow.begin(),s.follow.end());
  }

  bool operator > (const sign &s) {
    //终结符<非终结符，否则按照name排名
    if(type==s.type) {
      return name.compare(s.name)>0;
    }
    return type==1;
  }

  friend ostream& operator << (ostream& out , const sign & si) {
    out<<"name: "+si.name<<"   类型: "<<si.type<<endl;
    if(si.first.size()>0) {
      out<<"first集: ";
      for(auto s:si.first) {
        out<<s<<"  ";
      }
      out<<endl;
    }
    if(si.follow.size()>0) {
      out<<"follow集: ";
      for(auto s:si.follow) {
        out<<s<<"  ";
      }
      out<<endl;
    }
    out<<"--------------------------------------------------------------\n";
  }
};
//项目中的所有文法符号，包括终结符和非终结符
extern std::vector<sign> signs;


//产生式
struct formula {
  string from; //产生式左部
  std::vector<sign> rights;  //产生式右部数组
  formula(){};
  formula(std::vector<string> v);
};
//文法的所有产生式数组
extern std::vector<formula> formulas;


//项目中的条目
struct item {
  int formula_id; //使用的产生式在formulas中的索引
  int p; //产生式右部中的当前位置偏移

  item(){  p = 0; };
  item(int id) { formula_id = id; p = 0; };
  item(int id,int offset) { formula_id = id; p = offset; };

  sign get_cur_sign();
};
struct project_goto {
  string word;
  int project_id;
  project_goto() {};
  project_goto(string w,int id) { word = w; project_id = id; };
};
struct project_ret {
  int formula_id; //归约使用产生式id
  project_ret(int id) { formula_id = id; };
};
//项目
struct project {
  std::vector<item> items;
  std::vector<project_goto> go_table; //该项目的跳转条目表
  std::vector<project_ret> ret_table; //该项目的归约条目表

  void add_item(const item &); //在items中加入一条item
  void flash_ret_table(); //检查项目中是否有归约条目，如果有，就将归约项放入ret_table
  void e_closer(); //计算闭包

  bool operator == (const project& pro) {
    if(items.size()!=pro.items.size())
      return false;
    for(auto it1:items) {
      bool flag = false;
      for(auto it2:pro.items) {
        if(it1.formula_id==it2.formula_id&&it1.p==it2.p) {
          flag = true;
          break;
        }
      }
      if(!flag)
        return false;
    }
    return true;
  }
  friend ostream& operator << (ostream & out,const project & pro) {
    //打印项目中的文法条目
    out<<"条目:"<<endl;
    for(auto i:pro.items) {
      out<<formulas[i.formula_id].from<<" --> ";
      std::vector<sign> *v = &(formulas[i.formula_id].rights);
      int len = v->size();
      for(int j=0;j<len;j++) {
        if(j==i.p)
          out<<". ";
        out<<v->at(j).name<<" ";
      }
      if(i.p==len)
        out<<". ";
      out<<endl;
    }
    //打印项目的goto
    if(pro.go_table.size()>0) {
      out<<"goto:"<<endl;
      for(auto i:pro.go_table) {
        out<<"( "<<i.word<<" , "<<i.project_id<<" )  ";
      }
      out<<endl;
    }
    if(pro.ret_table.size()>0) {
      //打印归约项目
      out<<"ret:";
      for(auto i:pro.ret_table) {
        out<<i.formula_id<<"\t";
      }
      out<<endl;
    }
    out<<"-----------------------------------------------------------------------"<<endl;
  }
};
//根据文法生成的项目数组
extern std::vector<project> projects;


//用formula_s构造产生式并加入formulas
void create_forumla_into_formulas(string formula_s);
//从formulas中找到所有左部为sign_s的文法，并返回其索引
std::vector<int> get_formula_indexs_start_with_s(string sign_s);

//在signs中加入新的符号
void add_sign_into_signs(string sign_s);
//将signs中的符号按照 终结符<非终结符 的顺序排序
void sort_signs();
//在signs中找到sign_s对应的索引
int get_sign_index(string sign_s);

//在projects中加入project并返回project在projects中的索引
int add_project_into_projects(project &pro);

//打印状态
void display_table();
//将结果写到csv中
void write_to_csv(string filename);


#endif
